<?php
/***************************************************************************
 * 
 * Copyright (c) 2010 , Inc. All Rights Reserved
 * $Id$:hapn.php,2010/05/07 13:57:27 
 * 
 **************************************************************************/
 
 
 
/**
 * @file BaseApp.php
 * @author huqingping
 * @date 2010/05/07 13:57:27
 * @version 1.0 
 * @brief 
 *  
 **/

class BaseApp
{
	//true/false/manual
	public $debug = false;
	public $needLogCov = false;
	public $mode = '';
	public $timer = null;
	public $encoding = 'UTF-8';
	public $endStatus = 'init';
	public $appId = 0;

	function __construct()
	{
		$this->internalInit();
		$this->timer = LibUtil::load('EXTimer');
	}

	function init() 
	{
		$this->appId = $this->genAppId();
		global $__HapN_appid;
		$__HapN_appid = $this->appId;

		$this->_initConf();
		$this->_initEnv();
		$this->_initLog();
		if (true !== Conf::get('hapn.disable_apiproxy')) {
			//没有强制关闭
			$this->_initApiProxy();
		}
		if (true !== Conf::get('hapn.disable_db')) {
			//没有强制关闭
			$this->_initDB();
		}
	}
	function process() {}

	function run()
	{
		$this->timer->begin('total', 'init');
		$this->init();
		$this->timer->end('init');
		$this->timer->begin('process');
		$this->process();
		$this->timer->end('process');
		$this->endStatus = 'ok';
	}

	function genAppId()
	{
		$time = gettimeofday();
		$time = $time['sec'] * 100 + $time['usec'];
		$rand = mt_rand(1, $time+$time);
		$id = ($time ^ $rand)  & 0xFFFFFFFF;
		return floor($id/100)*100;
	}	

	protected function internalInit()
	{
		$path = get_include_path();
		$path = LIB_ROOT.PATH_SEPARATOR.EXLIB_ROOT.PATH_SEPARATOR.$path;
		set_include_path($path);
		require_once FR_ROOT.'core/Log.php';
		require_once FR_ROOT.'core/Conf.php';
		require_once LIB_ROOT.'libutil/LibUtil.php';
	}

	protected function _initEnv()
	{
		mb_internal_encoding($this->encoding);
		iconv_set_encoding("internal_encoding", $this->encoding);
		error_reporting(E_ALL|E_STRICT|E_NOTICE);
		//
		set_error_handler(array($this,'errorHandler'));
		set_exception_handler(array($this,'exceptionHandler'));
		register_shutdown_function(array($this,'shutdownHandler'));
	}

	protected function _initConf()
	{
		$confs = array(
			CONF_ROOT.'hapn.conf.php',
		);
		Conf::load($confs);
		$this->debug = Conf::get('hapn.debug',false);
		if ($this->mode == 'web') {
			$this->debug==='manual'?($this->debug=!empty($_GET['_d'])):"";
		} else {
			$args = getopt('d:');
			$this->debug==='manual'?($this->debug=!empty($args['d'])):"";
		}
		$this->encoding = strtoupper(Conf::get('hapn.encoding',$this->encoding));
		$this->needLogCov = Conf::get('hapn.logcov') && function_exists('xdebug_get_code_coverage');
		if ($this->needLogCov) {
			xdebug_start_code_coverage(XDEBUG_CC_UNUSED);
		}
		if ($this->debug) {
			ini_set('display_errors',1);
		}
	}
	
	private function _initLog()
	{
		$logFile = Conf::get('hapn.log.file','HapN');
		$logLevel = Conf::get('hapn.log.level',$this->debug?Logger::LOG_DEBUG:Logger::LOG_TRACE);
		if ($this->debug === true) {
			//DEBUG模式下log级别直接为debug
			$logLevel = Logger::LOG_DEBUG;
		}
		$roll = Conf::get('hapn.log.roll',Logger::NONE_ROLLING);
		Logger::init(LOG_ROOT,$logFile,$logLevel,array(),$roll);
		
		$basic = array('logid'=>$this->appId);
		Logger::addBasic($basic);
	}

	function _initApiProxy()
	{
		require_once LIB_ROOT.'apiproxy/ApiProxy.php';
		$servers = Conf::get('apiproxy.servers',array());
		if ($this->debug) {
			foreach($servers as $key=>$server) {
				//如果调试模式
				$servers[$key]['curlopt'][CURLOPT_VERBOSE] = true;
			}
		}
		$modmap = Conf::get('apiproxy.mod',array());
		$autogen = Conf::get('apiproxy.autodsl_root',array());
		ApiProxy::init(
			array(
				'servers'=>$servers,
				'mod'=>$modmap,
				'encoding'=>$this->encoding,
				'autodsl_root'=>$autogen
			), array(
				'app_root'=>APP_ROOT,
				'conf_root'=>CONF_ROOT,
			)
		);
		$intercepterclasses = Conf::get('apiproxy.intercepters',array());
		$intercepters = array();
		foreach($intercepterclasses as $class) {
			require_once PLUGIN_ROOT.'intercepters/'.$class.'.php';
			$intercepters[] = new $class();
		}
		ApiProxy::setGlobalIntercepters($intercepters);
	}

	function _initDB()
	{
		require_once LIB_ROOT.'db/Db.php';
		$conf = Conf::get('db.conf');
		$readonly = Conf::get('db.readonly',false);
		Db::init($conf);
		Db::setReadOnly(!!$readonly);
	}    

	function isUserErr($errcode)
	{
		$usererr = Conf::get('hapn.error.userreg','/\.u_/');
		return preg_match($usererr,$errcode) > 0;
	}

	function logCov()
	{
		$arr_cov = xdebug_get_code_coverage();
		$seq_arr_con = serialize($arr_cov);
		$path = TMP_ROOT.'cov/';
		if (is_writeable($path)) {
			$file = $path.$this->appId.'.cov';
			file_put_contents($file,$seq_arr_con,FILE_APPEND);
		} else {
			Logger::warning('no permission or no such direction %s',$path);
		}
	}

	function errorHandler()
	{
		$error = func_get_args();
		restore_error_handler();
		if (!($error[0] & error_reporting())) {
			Logger::debug('caught info, errno:%d,errmsg:%s,file:%s,line:%d',$error[0],$error[1],$error[2],$error[3]);
			set_error_handler(array($this,'errorHandler'));
			return false;
		} elseif ($error[0] === E_USER_NOTICE) {
			Logger::trace('caught trace, errno:%d,errmsg:%s,file:%s,line:%d',$error[0],$error[1],$error[2],$error[3]);
			set_error_handler(array($this,'errorHandler'));
			return false;
		} elseif ($error[0] === E_USER_WARNING) {
			Logger::warning('caught warning, errno:%d,errmsg:%s,file:%s,line:%d',$error[0],$error[1],$error[2],$error[3]);
			set_error_handler(array($this,'errorHandler'));
			return false;
		} elseif ($error[0] === E_USER_ERROR) {
			Logger::fatal('caught error, errno:%d,errmsg:%s,file:%s,line:%d',$error[0],$error[1],$error[2],$error[3]);
			set_error_handler(array($this,'errorHandler'));
			return false;
		} else {
			Logger::fatal('caught error, errno:%d,errmsg:%s,file:%s,line:%d',$error[0],$error[1],$error[2],$error[3]);
			$this->endStatus = 'error';
			return true;
		}
	}

	function exceptionHandler($ex)
	{
		restore_exception_handler();
		$errcode = $ex->getMessage();
		$errmsg = sprintf('caught exception, errcode:%s, trace: %s', $errcode,$ex->__toString());
		if (($pos = strpos($errcode,' '))) {
			$errcode = substr($errcode,0,$pos); 
		}
		$this->endStatus = $errcode;
		if ($this->isUserErr($errcode)){
			Logger::trace($errmsg);
		} else {
			Logger::fatal($errmsg);
		}
	}

	function shutdownHandler()
	{
		$result = $this->timer->getResult();
		$str[] = '[time:';
		foreach($result as $time) {
			$str[] = ' '.$time[0].'='.$time[1];
		}
		$str[] = ']';
		Logger::notice(implode('',$str).' status='.$this->endStatus);
		Logger::flush();

		if ($this->needLogCov) {
			$this->logCov();
		}
		
		if (true !== Conf::get('hapn.disable_db')) {
			//做一些清理
			TxScope::rollbackAll();
			Db::close();
		}
		
	}
}




/* vim: set ts=4 sw=4 sts=4 tw=100 noet: */
